﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace Titan
{
    internal static class LambdaHelper
    {
        public static IOrderExpression ToOrderExpression<T>(Expression<Func<T, OrderType>> expression)
        {
            MethodCallExpression methodCallExpression = (MethodCallExpression)expression.Body;
            string propertyName = null;
            if (methodCallExpression.Arguments[0] is UnaryExpression)
            {
                UnaryExpression unaryExpression = (UnaryExpression)methodCallExpression.Arguments[0];
                propertyName = GetPropertyName((MemberExpression)unaryExpression.Operand);
            }
            else if (methodCallExpression.Arguments[0] is MemberExpression)
            {
                propertyName = GetPropertyName((MemberExpression)methodCallExpression.Arguments[0]);
            }
            else
            {
                throw new InvalidOperationException(string.Format("未识别的类型",methodCallExpression.Arguments[0]));
            }
            OrderType orderType = OrderType.Asc;
            switch (methodCallExpression.Method.Name)
            { 
                case "Desc":
                    orderType = OrderType.Desc;
                    break;
                default:
                    //默认为asc
                    break;
            }
            return new OrderExpression(propertyName, orderType);
        }
        public static IPropertyExpression ToPropertyExpression<T>(Expression<Func<T, object>> expression)
        {
            UnaryExpression unaryExpression=(UnaryExpression)expression.Body;
            string propertyName = GetPropertyName((MemberExpression)unaryExpression.Operand);
            return new PropertyExpression(propertyName);
        }
        public static IConditionExpression ToConditionExpression<T>(Expression<Func<T, bool>> expression)
        {
            return ToConditionExpression(expression.Body); 
        }

        private static IConditionExpression ToConditionExpression(Expression expression)
        {
            //Console.WriteLine(expression.NodeType);
            switch (expression.NodeType)
            {
                case ExpressionType.Not:
                    IConditionExpression conditionExpression = ToConditionExpression(((UnaryExpression)expression).Operand);
                    conditionExpression.Not();
                    return conditionExpression;
                case ExpressionType.AndAlso:
                case ExpressionType.OrElse:
                    ConditionCollection conditionCollection = new ConditionCollection();
                    conditionCollection.Add(ToConditionExpression(((BinaryExpression)expression).Left));
                    conditionCollection.Add(ToConditionExpression(((BinaryExpression)expression).Right));
                    conditionCollection.ConditionRelation = expression.NodeType == ExpressionType.AndAlso ? ConditionRelation.And : ConditionRelation.Or;
                    return conditionCollection;
                case ExpressionType.GreaterThan:
                case ExpressionType.GreaterThanOrEqual:
                case ExpressionType.Equal:
                case ExpressionType.NotEqual:
                case ExpressionType.LessThan:
                case ExpressionType.LessThanOrEqual:
                    BinaryExpression binaryExpression = (BinaryExpression)expression;
                    string propertyName = GetPropertyName((MemberExpression)binaryExpression.Left);
                    //object conditionValue = Expression.Lambda<Func<object>>(binaryExpression.Right).Compile().Invoke();
                    object conditionValue = Expression.Lambda(binaryExpression.Right).Compile().DynamicInvoke();

                    ConditionOperator conditionOperator = ConditionOperator.Equal;
                    switch (expression.NodeType)
                    {
                        case ExpressionType.GreaterThan:
                            conditionOperator = ConditionOperator.GreaterThan;
                            break;
                        case ExpressionType.GreaterThanOrEqual:
                            conditionOperator = ConditionOperator.GreaterThanOrEqual;
                            break;
                        case ExpressionType.Equal:
                            conditionOperator = ConditionOperator.Equal;
                            break;
                        case ExpressionType.NotEqual:
                            conditionOperator = ConditionOperator.NotEqual;
                            break;
                        case ExpressionType.LessThan:
                            conditionOperator = ConditionOperator.LessThan;
                            break;
                        case ExpressionType.LessThanOrEqual:
                            conditionOperator = ConditionOperator.LessThanOrEqual;
                            break;
                    }
                    ConditionItem conditionItem = new ConditionItem(propertyName, conditionOperator, conditionValue);
                    return conditionItem;
                case ExpressionType.Call:
                    MethodCallExpression methodCallExpression = (MethodCallExpression)expression;
                    string propertyName2 = GetPropertyName((MemberExpression)methodCallExpression.Arguments[0]);
                    object conditionValue2 = Expression.Lambda(methodCallExpression.Arguments[1]).Compile().DynamicInvoke();
                    ConditionOperator conditionOperator2 = ConditionOperator.Equal;
                    switch (methodCallExpression.Method.Name)
                    {
                        case "GreaterThan":
                            conditionOperator2 = ConditionOperator.GreaterThan;
                            break;
                        case "GreaterEqual":
                            conditionOperator2 = ConditionOperator.GreaterThanOrEqual;
                            break;
                        case "LessThan":
                            conditionOperator2 = ConditionOperator.LessThan;
                            break;
                        case "LessEqual":
                            conditionOperator2 = ConditionOperator.LessThanOrEqual;
                            break;
                        case "Equals":
                            conditionOperator2 = ConditionOperator.Equal;
                            break;
                        case "Like":
                        case "Contains":
                            conditionOperator2 = ConditionOperator.Like;
                            break;
                        case "LeftLike":
                        case "StartsWith":
                            conditionOperator2 = ConditionOperator.LeftLike;
                            break;
                        case "RightLike":
                        case "EndsWith":
                            conditionOperator2 = ConditionOperator.RightLike;
                            break;
                        case "FullTextLike":
                            conditionOperator2 = ConditionOperator.FullTextLike;
                            break;
                        case "NotLike":
                            conditionOperator2 = ConditionOperator.NotLike;
                            break;
                        case "NotLeftLike":
                            conditionOperator2 = ConditionOperator.NotLeftLike;
                            break;
                        case "NotRightLike":
                            conditionOperator2 = ConditionOperator.NotRightLike;
                            break;
                        case "NotFullTextLike":
                            conditionOperator2 = ConditionOperator.NotFullTextLike;
                            break;
                        case "In":
                            conditionOperator2 = ConditionOperator.In;
                            break;
                        case "NotIn":
                            conditionOperator2 = ConditionOperator.NotIn;
                            break;
                        default:
                            throw ExceptionFactory.NotSupportedLambdaMethod(methodCallExpression, methodCallExpression.Method.Name);
                    }
                    ConditionItem conditionItem2 = new ConditionItem(propertyName2, conditionOperator2, conditionValue2);
                    return conditionItem2;
                default:
                    throw ExceptionFactory.NotSupportedLambda(expression);
            }

        }
        private static string GetPropertyName(MemberExpression expression)
        {
            StringBuilder sb = new StringBuilder();
            GetPropertyName(sb, expression);
            return sb.ToString();
        }
        private static void GetPropertyName(StringBuilder sb, MemberExpression expression)
        { 
            if (sb.Length > 0) sb.Insert(0, '.');
            sb.Insert(0, expression.Member.Name);
            if (expression.Expression is MemberExpression)
            {
                GetPropertyName(sb, (MemberExpression)expression.Expression);
            }
            else if (expression.Expression is ParameterExpression)
            {
            }
            else
            {
                throw ExceptionFactory.NotSupportedLambdaProperty(expression.Expression);
            }
        }

       
    }
}
